using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ace;
using Ace.Web;
using System.Windows;
using System.IO;
using System.Diagnostics;
using System.Net;
using System.Reflection;
using System.Threading;
using MalwarePatch.Languages;
using MalwarePatch.Windows.Main;

namespace MalwarePatch.Models
{
  sealed class Updater
  {
    /// <summary>
    /// 更新源的ID
    /// </summary>
    private const string UpdateId = "0B4uebmDoSFx-c0kzcG5yVlZVMlE";
    public static readonly string UpdateUrl = "https://github.com/the1812/Malware-Patch/releases";

    public string Proxy { get; set; }
    private UpdateLanguage Languages { get; } = new UpdateLanguage();
    public DownloadProgressChangedEventHandler ProgressChanged { get; set; }

    public const string
        UpdateFileName = "__mwp.exe",
        UpdateParameter = "--update",
        RestartParameter = "--restart",
        RemoveOldFileParameter = "--remove";
    public Task<FileInfo> DownloadUpdate()
    {
      if (Process.GetCurrentProcess().MainModule.FileName.GetFileName() == UpdateFileName)
      {
        var message = Languages[UpdateLanguage.Keys.UpdateFromPreupdateFile];
        throw new InvalidOperationException(message);
      }
      if (File.Exists(UpdateFileName))
      {
        File.Delete(UpdateFileName);
      }
      var folderName = BuildConfig.IsUnbundled ? "unbundled" : "bundled";
      var downloadLink = $"https://github.com/the1812/malware-patch/raw/master/dist/{folderName}/mwp.exe";
      var info = new DownloadInfo(downloadLink)
      {
        Proxy = Proxy,
        ProgressChanged = ProgressChanged,
      };
      return info.DownloadFileAsync(UpdateFileName);
    }
    public string RestartParameters { get; set; } = "";
    public void SetUpdatePlan()
    {
      Application.Current.Exit += (s, e) =>
      {
        if (File.Exists(UpdateFileName))
        {
          var startInfo = new ProcessStartInfo(UpdateFileName)
          {
            Arguments = $"{UpdateParameter}={(Process.GetCurrentProcess().MainModule.FileName.GetFileName()).Quotes()} {RestartParameters}",
            WorkingDirectory = Environment.CurrentDirectory,
            UseShellExecute = false,
          };
          Process.Start(startInfo);
        }
      };
    }
    /// <summary>
    /// 安装更新(如果有)并启动应用
    /// </summary>
    /// <param name="app">应用</param>
    /// <param name="args">命令行参数</param>
    public static void InstallUpdateAndRun(App app, string[] args)
    {
      const int maxWaitTimes = 60;
      var waitTimes = 0;
      void removeUpdateFile()
      {
        var selfFileName = Process.GetCurrentProcess().MainModule.FileName.GetFileName();
        var fileNameToRemove = UpdateFileName;
        if (selfFileName != fileNameToRemove
            && File.Exists(fileNameToRemove))
        {
          //Ensure the old app has exited
          while (Utils.IsRunning(fileNameToRemove))
          {
            Thread.Sleep(500);
            waitTimes++;
            if (waitTimes > maxWaitTimes)
            {
              app.Shutdown();
            }
          }
          Thread.Sleep(500);
          File.Delete(fileNameToRemove);
        }
      }
      void copyUpdateFile(Dictionary<string, string> dictionary)
      {
        var targetFileName = dictionary[UpdateParameter].NoQuotes();
        var selfFileName = Process.GetCurrentProcess().MainModule.FileName.GetFileName();
#if DEBUG
        //MessageBox.Show(targetFileName, selfFileName);
#endif
        if (!selfFileName.EqualsIgnoreCase(targetFileName))
        {
          //Ensure the old app has exited
          while (Utils.IsRunning(targetFileName))
          {
            Thread.Sleep(500);
            waitTimes++;
            if (waitTimes > maxWaitTimes)
            {
              app.Shutdown();
            }
          }
          //Thread.Sleep(500);
          File.Copy(selfFileName, targetFileName, true);
          Process.Start(new ProcessStartInfo
          {
            FileName = targetFileName,
            WorkingDirectory = Environment.CurrentDirectory,
            Arguments = RemoveOldFileParameter,
          });
          //Check if restart is required
          if (dictionary.ContainsKey(RestartParameter))
          {
            var arguments = new Dictionary<string, string>(dictionary);
            arguments.Remove(RestartParameter);
            arguments.Remove(UpdateParameter);
            Process.Start(new ProcessStartInfo
            {
              Arguments = string.Join(" ", arguments.Select(kv =>
              {
                if (kv.Value is null)
                {
                  return kv.Key;
                }
                else
                {
                  return $"{kv.Key}={kv.Value}";
                }
              })),
              FileName = targetFileName,
              WorkingDirectory = Environment.CurrentDirectory,
            });
          }
        }
      }
      if ((args?.Length ?? -1) > 0)
      {
        var oldVersionParameter = $"{UpdateParameter}:";
        var flattenedArgs = string.Join(" ", args);
        Dictionary<string, string> dictionary = null;
        if (!flattenedArgs.Contains(oldVersionParameter))
        {
          dictionary = flattenedArgs.SplitToDictionary(" ", "=", true);
        }
        else
        {
          dictionary = flattenedArgs.SplitToDictionary(" ", ":", true);
        }
#if DEBUG
        File.AppendAllText("args.txt", Environment.NewLine + flattenedArgs);
#endif

        if (dictionary.ContainsKey(UpdateParameter))
        {
          copyUpdateFile(dictionary);
        }
        else if (dictionary.ContainsKey(RemoveOldFileParameter))
        {
          removeUpdateFile();
        }
      }
      else
      {
        new MainWindow().ShowDialog();
      }
      app.Shutdown();
    }
  }
}
